///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __CompositorChain_H__
#define __CompositorChain_H__

#include "OgrePrerequisites.h"
#include "OgreRenderTargetListener.h"
#include "OgreRenderQueueListener.h"
#include "OgreCompositorInstance.h"
#include "OgreCompositor.h"
#include "OgreViewport.h"

namespace Ogre {
	
	
	
	class _OgreExport CompositorChain : public RenderTargetListener, public Viewport::Listener, public MemAlloc_Resource
	{
	public:
        CompositorChain(Viewport *vp);
        
        virtual ~CompositorChain();
        
        /// Data types
        typedef vector<CompositorInstance*>::type Instances;
        typedef VectorIterator<Instances> InstanceIterator;
        
        /// Identifier for "last" compositor in chain
        static const size_t LAST = (size_t)-1;
        /// Identifier for best technique
        static const size_t BEST = 0;
        
        
		CompositorInstance* addCompositor(CompositorPtr filter, size_t addPosition=LAST, const String& scheme = StringUtil::BLANK);

        
        void removeCompositor(size_t position=LAST);
        
        
        size_t getNumCompositors();
        
        
        void removeAllCompositors();
        
        
        CompositorInstance *getCompositor(size_t index);

		
        CompositorInstance *getCompositor(const String& name);

		
		CompositorInstance* _getOriginalSceneCompositor(void) { return mOriginalScene; }

        
        InstanceIterator getCompositors();
    
        
        void setCompositorEnabled(size_t position, bool state);

        
		virtual void preRenderTargetUpdate(const RenderTargetEvent& evt);
		
		virtual void postRenderTargetUpdate(const RenderTargetEvent& evt);
		
        virtual void preViewportUpdate(const RenderTargetViewportEvent& evt);
        
        virtual void postViewportUpdate(const RenderTargetViewportEvent& evt);

		
		virtual void viewportCameraChanged(Viewport* viewport);
		
		virtual void viewportDimensionsChanged(Viewport* viewport);
		
		virtual void viewportDestroyed(Viewport* viewport);

        
        void _markDirty();
        
        
        Viewport *getViewport();

		
        void _removeInstance(CompositorInstance *i);

		
		void _queuedOperation(CompositorInstance::RenderSystemOperation* op);

		
		void _compile();

		
		CompositorInstance* getPreviousInstance(CompositorInstance* curr, bool activeOnly = true);
		
		CompositorInstance* getNextInstance(CompositorInstance* curr, bool activeOnly = true);

	protected:
        /// Viewport affected by this CompositorChain
        Viewport *mViewport;
        
        
        CompositorInstance *mOriginalScene;
        
        /// Postfilter instances in this chain
        Instances mInstances;
        
        /// State needs recompile
        bool mDirty;
		/// Any compositors enabled?
		bool mAnyCompositorsEnabled;

		String mOriginalSceneScheme;

        /// Compiled state (updated with _compile)
        CompositorInstance::CompiledState mCompiledState;
        CompositorInstance::TargetOperation mOutputOperation;
		/// Render System operations queued by last compile, these are created by this
		/// instance thus managed and deleted by it. The list is cleared with 
		/// clearCompilationState()
		typedef vector<CompositorInstance::RenderSystemOperation*>::type RenderSystemOperations;
		RenderSystemOperations mRenderSystemOperations;

		
		void clearCompiledState();
        
        
        void preTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam);
        
        
        void postTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam);

		void createOriginalScene();
		void destroyOriginalScene();

		/// destroy internal resources
		void destroyResources(void);

		
		class _OgreExport RQListener: public RenderQueueListener
		{
		public:
			
			virtual void renderQueueStarted(uint8 id, const String& invocation, bool& skipThisQueue);
			
			virtual void renderQueueEnded(uint8 id, const String& invocation, bool& repeatThisQueue);

			
			void setOperation(CompositorInstance::TargetOperation *op,SceneManager *sm,RenderSystem *rs);

			
			void notifyViewport(Viewport* vp) { mViewport = vp; }

			
			void flushUpTo(uint8 id);
		private:
			CompositorInstance::TargetOperation *mOperation;
			SceneManager *mSceneManager;
			RenderSystem *mRenderSystem;
			Viewport* mViewport;
			CompositorInstance::RenderSystemOpPairs::iterator currentOp, lastOp;
		};
		RQListener mOurListener;
		/// Old viewport settings
		unsigned int mOldClearEveryFrameBuffers;
		/// Store old scene visibility mask
		uint32 mOldVisibilityMask;
		/// Store old find visible objects
		bool mOldFindVisibleObjects;
		/// Store old camera LOD bias
		float mOldLodBias;
		///	Store old viewport material scheme
		String mOldMaterialScheme;
		/// Store old shadows enabled flag
		bool mOldShadowsEnabled;

    };
	
	
}

#endif
